﻿using System;

namespace Fetches.Fetch.Utils.IdGenerator
{
    public class IdTimer
    {
        public const long EPOCH = 1420041600000L;//  /** 开始时间截 (2015-01-01) */
        protected IdMeta IdMeta;
        protected IdType IdType;
        protected long MaxTime;
        protected long epoch = EPOCH;

        public void Init(IdMeta idMeta, IdType idType)
        {
            this.IdMeta = idMeta;
            this.MaxTime = (1L << idMeta.GetTimeBits()) - 1;//不写作1L的话c#默认把这里当int在计算
            this.IdType = idType;
            this.GenTime();
        }

        public void ValidateTimestamp(long lastTimestamp, long timestamp)
        {
            if (timestamp < lastTimestamp)
            {
                throw new ArgumentException(
                        String.Format(
                                "Clock moved backwards.  Refusing to generate id for %d second/milisecond.",
                                lastTimestamp - timestamp));
            }
        }

        public long TillNextTimeUnit(long lastTimestamp)
        {

            long timestamp = GenTime();
            while (timestamp <= lastTimestamp)
            {
                timestamp = GenTime();
            }
            return timestamp;
        }

        public DateTime TransTime(long time)
        {
            return IdType == IdType.Milliseconds ?
                TimestampHelper.FromMilliseconds(time + epoch) : TimestampHelper.FromMilliseconds(time * 1000 + epoch);
        }

        /// <summary>
        /// 产生时间戳
        /// </summary>
        /// <param name="dateTime">需要注意的是使用的是UTC时间</param>
        /// <returns></returns>
        public long GenTime(DateTime? dateTime=null)
        {
            var currentTicks = dateTime?.Ticks ?? DateTime.UtcNow.Ticks;

            DateTime dtFrom = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            long currentMillis = (currentTicks - dtFrom.Ticks) / 10000;

            long time;
            if (IdType == IdType.Milliseconds)
            {
                time = currentMillis - epoch;
            }
            else
            {
                time = (currentMillis - epoch) / 1000;
            }
            ValidateTimestamp(time);
            return time;
        }

        protected void ValidateTimestamp(long timestamp)
        {
            if (timestamp > MaxTime)
            {
                throw new ArgumentException(
                    string.Format("The current timestamp ({0} >= {1}) has overflowed, Vesta Service will be terminate.",
                        timestamp, MaxTime));
            }
        }
    }
}
